package com.pep.mgmt.service;

import java.util.ArrayList;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;

@Aspect
@Slf4j
@Component
public class WebLogAspect {

    // 创建一个线程空间，来存放接口执行的开始毫秒数
    private ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    //@Pointcut("@within(org.springframework.stereotype.Controller) || @within(org.springframework.web.bind.annotation.RestController)")
    //@Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
    //@Pointcut("execution (* com.pep.mgmt.controller.*.*(..))")
    @Pointcut("execution (com.pep.mgmt.util.Result<Object> com.pep.mgmt.controller.*.*(..))")
    public void cutController() {
    }

    @Before("cutController()")
    public void doBefore(JoinPoint point) {
        log.info("doBefore {}", point.getSignature().getName());
        // 保存接口开始执行的时间
        long startTime = System.currentTimeMillis();
        threadLocal.set(startTime);

        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        if (servletRequestAttributes == null) {
            log.warn("servletRequestAttributes is null");
            return ;
        }

        //获取拦截方法的参数
        HttpServletRequest request = servletRequestAttributes.getRequest();

        if (request != null) {
            String url = request.getRequestURL().toString();
            List<Object> list = new ArrayList<>();
            for (Object object : point.getArgs()) {
                if (object instanceof MultipartFile || object instanceof HttpServletRequest || object instanceof HttpServletResponse || object instanceof BindingResult) {
                    continue;
                }
                list.add(object);
            }
            //log.info("请求 uri:[{}],params:[{}]", url, StringUtils.join(list, ","));
            log.info("请求 uri:[{}],params:[{}]", url, list.toString());
        }

    }

    /**
     * 返回通知：
     * 1. 在目标方法正常结束之后执行
     * 1. 在返回通知中补充请求日志信息，如返回时间，方法耗时，返回值，并且保存日志信息
     *
     * @param response
     * @throws Throwable
     */
    @AfterReturning(returning = "response", pointcut = "cutController()")
    public void doAfterReturning(JoinPoint jp, Object response) {
        log.info("doAfterReturning {}", jp.getSignature().getName());

		// 通过线程空间存储的接口开始时间计算接口耗时
        Long startTime = threadLocal.get();
        long endTime = System.currentTimeMillis();
        log.info("process time {}ms", endTime - startTime);

        if (response != null) {
            //log.info("请求返回result:[{}]", JSONUtil.toJsonStr(response));
            log.info("请求返回result:[{}]", response.toString());
        }
    }

}
